﻿#include "server.h"
#include "socketlibfunction.h"
#include <iostream>
#include <assert.h>

using namespace std;
using namespace SocketLib;

BaseSocket::BaseSocket()
{
    m_server = NULL;
    m_recvBuffer = NULL;
    _init();
}

BaseSocket::~BaseSocket()
{
    if(NULL != m_recvBuffer)
    {
        delete m_recvBuffer;
        m_recvBuffer = NULL;
    }

    if(SOCKET_ERROR != m_sock)
    {
        SocketApi::CloseSocket(m_sock);
        m_sock = SOCKET_ERROR;
    }
}

void BaseSocket::onClose()
{
}

void BaseSocket::onConnection()
{
}

void BaseSocket::onRecved()
{
}

#if defined PLATFORM_LINUX
bool BaseSocket::isReadable()
{
    return m_readable;
}
bool BaseSocket::isWriteable()
{
    return m_writeable;
}
#endif

void* BaseSocket::getServer()
{
    return m_server;
}

ESocketStatus BaseSocket::getStatus()
{
    return m_status;
}

void BaseSocket::writeBuffer(const char* buffer, int size)
{
    m_sendMutex.lock();
    m_sendBuffer.writeBuffer(buffer, size);
    m_sendMutex.unLock();
}

void BaseSocket::adjustRecvBuffer()
{
    const static int MIN_ADJUST_SIZE = 10;

    assert(NULL != m_recvBuffer);

    if(NULL != m_recvBuffer)
    {
        // 当接收数据在缓冲区的较后部,调整接收缓冲区数据到缓冲区头部
        int canWriteSize = m_recvBuffer->getSize() - m_recvBuffer->getWritePos();
        if(canWriteSize <= MIN_ADJUST_SIZE)
        {
            m_recvBuffer->adjustToHead();
        }
    }
}

const char* BaseSocket::getIP()
{
    return m_ip;
}

void BaseSocket::_setSock(sock ASock)
{
    m_sock = ASock;
}

sock BaseSocket::_getSock()
{
    return m_sock;
}

void BaseSocket::_init()
{
    m_sock = SOCKET_ERROR;
    m_sendMutex.lock();
    m_sendBuffer.init();
    m_sendMutex.unLock();
    memset(m_ip, 0, sizeof(m_ip));
    m_port = -1;
    m_status = ESocketFree;
    #if defined PLATFORM_LINUX
    m_readable = false;
    m_writeable = false;
    #endif
}

void BaseSocket::_setServer(void* p)
{
    m_server = p;
}

void BaseSocket::_setIPAddress(struct sockaddr_in& AAddr)
{
    m_port = htons(AAddr.sin_port);
    char* addr = inet_ntoa(AAddr.sin_addr);
    if(NULL != addr)
    {
        strcpy(m_ip, addr);
    }
    else
    {
        cout << "get ip failed" << endl;
    }
}

bool BaseSocket::_recvSelectData()
{
    assert(NULL != m_recvBuffer);

    int len = 1;

    if(NULL != m_recvBuffer)
    {
        // 当前接收缓冲区可写大小
        int canWriteSize = m_recvBuffer->getSize() - m_recvBuffer->getWritePos();
        if(canWriteSize > 0)
        {
            len = recv(m_sock, m_recvBuffer->getWriteBuffer(), canWriteSize, 0);
            if(len <= 0)
            {
                if(SOCKET_ERROR == len && S_EWOULDBLOCK == sErrno)
                {
                    //set sucess
                    len = 1;
                }
            }
            else
            {
                m_recvBuffer->addWritePos(len);
            }
        }
    }

    //if len <= 0, socket is close or error
    return len > 0;
}

EEpollRecvResult BaseSocket::_recvEpollData()
{
    // epoll模式下读取数据,直到出错为止
    int eRecvResult = ERecvBufferSmall;

    assert(NULL != m_recvBuffer);

    if(NULL != m_recvBuffer)
    {
        do
        {
            int canWriteSize = m_recvBuffer->getSize() - m_recvBuffer->getWritePos();
            if(canWriteSize <= 0)
            {
                break;
            }

            int len = recv(m_sock, m_recvBuffer->getWriteBuffer(), canWriteSize, 0);

            if(0 == len)
            {
                eRecvResult = ERecvCLOSE;
                break;
            }
            else if(SOCKET_ERROR == len && S_EWOULDBLOCK == sErrno)
            {
                eRecvResult |= ERecvEAGIN;
                break;
            }
            else
            {
                m_recvBuffer->addWritePos(len);
                eRecvResult |= ERecvOK;
            }
        }while(true);
    }

    return (EEpollRecvResult)eRecvResult;
}

bool BaseSocket::_sendSelectData()
{
    int leftSize = m_sendBuffer.getUsableSize();
    bool isok = true;

    if(leftSize > 0)
    {
        m_sendMutex.lock();

        int sendSize = SocketApi::SendData(m_sock, m_sendBuffer.getReadBuffer(), leftSize);
        if(sendSize > 0)
        {
            m_sendBuffer.addReadPos(sendSize);
        }
        else if(sendSize < 0)
        {
            isok = false;
        }

        m_sendMutex.unLock();
    }

    return isok;
}

EEpollSendResult BaseSocket::_sendEpollData()
{
    // epoll模式下发送数据,直到出错为止
    int eResult = ESendOK;
    
    int leftSize = m_sendBuffer.getUsableSize();
    if(leftSize > 0)
    {
        m_sendMutex.lock();

        do
        {
            int sendSize = send(m_sock, m_sendBuffer.getReadBuffer(), leftSize, 0);
            if(sendSize > 0)
            {
                m_sendBuffer.addReadPos(sendSize);
                if(sendSize < leftSize)
                {
                    eResult |= ESendEAGIN;
                    break;
                }
            }
            else if(0 == sendSize)
            {
                eResult = ESendCLOSE;
                break;
            }
            else if(SOCKET_ERROR == sendSize && S_EWOULDBLOCK == sErrno)
            {
                eResult |= ESendEAGIN;
                break;
            }

            leftSize = m_sendBuffer.getUsableSize();
            if(leftSize <= 0)
            {
                break;
            }
            
        }while(true);

        m_sendMutex.unLock();
    }

    return (EEpollSendResult)eResult;
}

void BaseSocket::_setStatus(ESocketStatus status)
{
    m_status = status;
}

#if defined PLATFORM_LINUX
void BaseSocket::_setReadable(bool b)
{
    m_readable = b;
}

void BaseSocket::_setWriteable(bool b)
{
    m_writeable = b;
}
#endif

BaseServer::BaseServer()
{
}

BaseServer::~BaseServer()
{

}

void BaseServer::_initBaseSocket(BaseSocket& ASocket)
{
    ASocket._init();
}

void BaseServer::_setBaseSocketSock(BaseSocket& ASocket, sock ASock)
{
    ASocket._setSock(ASock);
}

  sock BaseServer::_getSock(BaseSocket& ASocket)
{
    return ASocket._getSock();
}

void BaseServer::_setIPAddress(BaseSocket& ASocket, struct sockaddr_in& AAddr)
{
    ASocket._setIPAddress(AAddr);
}

void BaseServer::_setSocketOpts(sock ASock)
{
    if(!SocketApi::SetNonblock(ASock))
    {
        cout << "set noblock failed" << endl;
    }

    int yes = 1;
    setsockopt(ASock, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes));

    struct linger opt;
    opt.l_onoff = 0;
    opt.l_linger = 0;
    if(setsockopt(ASock, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)))
    {
        cout << "setsocketopts: Unable to set SO_LINGER mode for connection" << endl;
    }
}

void BaseServer::addAcceptSocket(sock ASock)
{
    m_acceptedList.pushElement(ASock);
}

void BaseServer::addCloseSocket(BaseSocket* p)
{
    m_mustCloseList.pushElement(p);
}

  bool BaseServer::_recvSelectData(BaseSocket& ASocket)
{
    return ASocket._recvSelectData();
}

EEpollRecvResult BaseServer::_recvEpollData(BaseSocket& ASocket)
{
    return ASocket._recvEpollData();
}

bool BaseServer::_sendSelectData(BaseSocket& ASocket)
{
    return ASocket._sendSelectData();
}

EEpollSendResult BaseServer::_sendEpollData(BaseSocket& ASocket)
{
    return ASocket._sendEpollData();
}

void BaseServer::_setServer(BaseSocket& ASocket)
{
    ASocket._setServer(this);
}

void BaseServer::_setStatus(BaseSocket& ASocket, ESocketStatus status)
{
    ASocket._setStatus(status);
}

void BaseServer::_setSocketOnConnected(BaseSocket& ASocket, sock ASockFD)
{
    struct sockaddr_in socketaddress;
    socklen_t size = sizeof(struct sockaddr);

    getpeername(ASockFD, (struct sockaddr*)&socketaddress, &size);

    ASocket._init();
    ASocket._setSock(ASockFD);
    ASocket._setIPAddress(socketaddress);
    _setSocketOpts(ASockFD);
    ASocket._setStatus(ESocketConnected);
}

#if defined PLATFORM_LINUX
void BaseServer::_setSocketReadable(BaseSocket& ASocket, bool b)
{
    ASocket._setReadable(b);
}

void BaseServer::_setSocketWriteable(BaseSocket& ASocket, bool b)
{
    ASocket._setWriteable(b);
}
#endif
